/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 combat_reader.h

	$Header: /heroes4/combat_reader.h $

	$NoKeywords: $

 ************************************************************************/
// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "combat_reader.h"

#include "castle_gate.h"
#include "checked_cast.h"
#include "combat_creature.h"
#include "combat_label.h"
#include "combat_object_registration.h"
#include "combat_object_type.h"
#include "compound_object.h"
#include "compound_object_model.h"
#include "quicksand.h"
#include "stationary_combat_object.h"
#include "streambuf_operators.h"

// factories
namespace
{
	t_combat_object_registration<t_castle_gate>	const				
					k_register_gate( k_combat_object_type_gate );
	t_combat_object_registration<t_combat_creature>	const	
					k_register_creature( k_combat_object_type_creature );
	t_combat_object_registration<t_combat_label> const				
					k_register_label( k_combat_object_type_label );
	t_combat_object_registration<t_compound_object> const	
					k_register_compound_object( k_combat_object_type_compound );
	t_combat_object_registration<t_quicksand> const					
					k_register_quicksand( k_combat_object_type_quicksand );
	t_combat_object_registration<t_stationary_combat_object> const	
					k_register_stationary_object( k_combat_object_type_stationary );
};

// -------------------------------------------------------------

t_combat_saveable_object::~t_combat_saveable_object()
{
}

// -------------------------------------------------------------

t_combat_saveable_object* t_combat_reader::read_object()
{
	t_uint32	id = get<t_uint32>( m_stream );

	if (id == 0)
		return 0;

	--id;
	if (id < m_objects.size())
		return m_objects[id];

	assert( id == m_objects.size() );
	if (id != m_objects.size())
		return 0;

	t_combat_object_type object_type;

	object_type = t_combat_object_type( get<t_int16>( m_stream ) );
	if (object_type < 0 || object_type >= k_combat_object_type_count)
		return 0;

	t_combat_saveable_object* result = create_combat_object( m_battlefield, object_type );

	if (result == 0)
		return 0;

	m_objects.push_back( result );
	result->read( *this );
	return result;
}

t_abstract_combat_object* t_combat_reader::read_abstract_object()
{
	return dynamic_cast<t_abstract_combat_object*>( read_object() );
}

t_attackable_obstacle* t_combat_reader::read_attackable_obstacle()
{
	return dynamic_cast<t_attackable_obstacle*>( read_object() );
}

t_combat_label* t_combat_reader::read_label()
{
	return dynamic_cast<t_combat_label*>( read_object() );
}

t_compound_object* t_combat_reader::read_compound_object()
{
	return dynamic_cast<t_compound_object*>( read_object() );
}

t_combat_creature* t_combat_reader::read_creature()
{
	return dynamic_cast<t_combat_creature*>( read_object() );
}

t_castle_gate* t_combat_reader::read_gate()
{
	return dynamic_cast<t_castle_gate*>( read_object() );
}

t_object_segment* t_combat_reader::read_segment()
{
	return dynamic_cast<t_object_segment*>( read_object() );
}

t_stationary_combat_object* t_combat_reader::read_stationary_object()
{
	return dynamic_cast<t_stationary_combat_object*>( read_object() );
}


// -------------------------------------------------------------

bool t_combat_writer::write( t_combat_saveable_object const* object )
{
	if (object == 0)
	{
		put<t_uint32>( m_stream, 0 );
		return true;
	}

	t_combat_saveable_object_const_ptr	object_ptr( object );
	t_object_indexed_array::iterator	result;

	result = m_objects.find( object_ptr );
	if (result == m_objects.end())
	{
		int	id = m_objects.size() + 1;

		m_objects.insert( std::make_pair( object_ptr, id ) );
		put<t_uint32>( m_stream, id );
		put<t_int16>( m_stream, object->get_object_type() );
		
		return object->write( *this );
	}
	put<t_uint32>( m_stream, result->second );
	return true;
}
